﻿using ErrorOr;
using Gym.Application.Common.Interfaces;
using Gym.Domain.Common.ValueObjects;
using Gym.Domain.SessionAggregate;
using MediatR;

namespace Gym.Application.Sessions.Commands.CreateSession
{
    public class CreateSessionCommandHandler : IRequestHandler<CreateSessionCommand, ErrorOr<Session>>
    {
        private readonly IRoomsRepository _roomsRepository;
        private readonly ITrainersRepository _trainersRepository;

        public CreateSessionCommandHandler(IRoomsRepository roomsRepository, ITrainersRepository trainersRepository)
        {
            _roomsRepository = roomsRepository;
            _trainersRepository = trainersRepository;
        }

        public async Task<ErrorOr<Session>> Handle(CreateSessionCommand request, CancellationToken cancellationToken)
        {
            var room = await _roomsRepository.GetByIdAsync(request.RoomId);            
            if (room is null)
            {
                return Error.NotFound(description: "没有找到该教室信息");
            }

            var trainer = await _trainersRepository.GetByIdAsync(request.TrainerId);
            if (trainer is null)
            {
                return Error.NotFound(description: "没有找到该教练信息");
            }

            var createTimeRangeResult = TimeRange.FromDateTimes(request.StartDateTime, request.EndDateTime);
            if (createTimeRangeResult.IsError && createTimeRangeResult.FirstError.Type == ErrorType.Validation)
            {
                return Error.Validation(description: "无效的日期和时间");
            }

            if (!trainer.IsTimeSlotFree(DateOnly.FromDateTime(request.StartDateTime), createTimeRangeResult.Value))
            {
                return Error.Validation(description: "教练的日程在整个课程期间都不空闲");
            }

            var session = new Session(
            name: request.Name,
            description: request.Description,
            maxParticipants: request.MaxParticipants,
            roomId: request.RoomId,
            trainerId: request.TrainerId,
            date: DateOnly.FromDateTime(request.StartDateTime),
            time: createTimeRangeResult.Value,
            categories: request.Categories);

            var scheduleSessionResult = room.ScheduleSession(session);

            if (scheduleSessionResult.IsError)
            {
                return scheduleSessionResult.Errors;
            }

            await _roomsRepository.UpdateAsync(room);

            return session;
        }
    }
}
